home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CICA Windows Explosion!
/
The CICA Windows Explosion! - Disc 2.iso
/
nt
/
emacssrc.zip
/
EMACSSRC.TAR
/
emacs-19.17
/
src
/
ntterm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-22
|
15KB
|
645 lines
/*
Terminal hooks for Windows NT(tm) port of GNU Emacs.
Copyright (C) 1992 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 1, or (at your option) any later
version.
GNU Emacs is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along
with GNU Emacs; see the file COPYING. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
Tim Fleehart (apollo@online.com) 17-Jan-92
Geoff Voelker (voelker@cs.washington.edu) 9-12-93 (updated to vers. 19)
*/
#include <stdlib.h>
#include <stdio.h>
#include "config.h"
#include <windows.h>
#include "lisp.h"
#include "frame.h"
#include "disptab.h"
#include "termhooks.h"
#include "ntterm_p.h"
#include "ntinevt_p.h"
#include "alloca_p.h"
extern FRAME_PTR updating_frame;
extern int meta_key;
static void MoveCursor(int row, int col);
static void ClearToEnd(void);
static void ClearFrame(void);
static void ClearEndOfLine(int);
static void InsDelLines(int vpos, int n);
static void ChangeLineHighlight(int, int, int);
static void ReassertLineHighlight(int, int);
static void InsertGlyphs(GLYPH *start, int len);
static void WriteGlyphs(GLYPH *string, int len);
static void DeleteGlyphs(int n);
static void RingBell(void);
static void ResetTerminalModes(void);
static void SetTerminalModes(void);
static void SetTerminalWindow(int size);
static void UpdateBegin(FRAME_PTR f);
static void UpdateEnd(FRAME_PTR f);
static void ResetKbd(void);
static void UnsetKbd(void);
static int HLmode(int new_highlight);
/*
Init hook called in init_keyboard
*/
void (*keyboard_init_hook)(void) = ResetKbd;
COORD Cursor;
HANDLE PrevScreen, CurScreen;
UCHAR CAttr, CAttrNormal, CAttrReverse;
HANDLE Keyboard;
/*
* CtrlCHandler for Windows NT (tm)
*
* Setting this as the ctrl handler prevents emacs from being killed when
* someone hits ^C in a 'suspended' session (child shell).
*/
BOOL WINAPI
CtrlCHandler(DWORD type)
{
if (type == CTRL_C_EVENT) {
return TRUE;
} else {
return FALSE;
}
}
/*
If we're updating a frame, use it as the current frame
Otherwise, use the selected frame
*/
#define PICK_FRAME() (updating_frame ? updating_frame : selected_frame)
/*
* move the cursor to (row, col)
*/
void
MoveCursor(int row, int col)
{
Cursor.X = col;
Cursor.Y = row;
if (updating_frame == NULL)
{
SetConsoleCursorPosition(CurScreen, Cursor);
}
}
/*
* clear from cursor to end of screen
*/
void
ClearToEnd(void)
{
FRAME_PTR f = PICK_FRAME();
ClearEndOfLine(FRAME_WIDTH(f) - 1);
InsDelLines(Cursor.Y, FRAME_HEIGHT(f) - Cursor.Y - 1);
}
/*
* clear the frame
*/
void
ClearFrame(void)
{
SMALL_RECT Scroll;
COORD Dest;
CHAR_INFO Fill;
FRAME_PTR f = PICK_FRAME();
HLmode(0);
Scroll.Top = 0;
Scroll.Bottom = FRAME_HEIGHT(f) - 1;
Scroll.Left = 0;
Scroll.Right = FRAME_WIDTH(f) - 1;
Dest.Y = FRAME_HEIGHT(f);
Dest.X = 0;
Fill.Char.AsciiChar = 0x20;
Fill.Attributes = CAttr;
ScrollConsoleScreenBuffer(CurScreen, &Scroll, NULL, Dest, &Fill);
MoveCursor(0, 0);
}
/*
* clear from Cursor to end (what's "standout marker"?)
*/
void
ClearEndOfLine(int end)
{
static GLYPH base[256];
static BOOL beenhere = FALSE;
if (!beenhere)
{
int i;
for (i = 0; i < 256; i++)
{
base[i] = SPACEGLYPH; /* empty space */
}
beenhere = TRUE;
}
WriteGlyphs(base, end - Cursor.X); /* fencepost ? */
}
/*
* insert n lines at vpos. if n is negative delete -n lines
*/
void
InsDelLines(int vpos, int n)
{
int i, nb, save_highlight;
SMALL_RECT Scroll;
COORD Dest;
CHAR_INFO Fill;
FRAME_PTR f = PICK_FRAME();
if (n < 0)
{
Scroll.Top = vpos - n;
Scroll.Bottom = FRAME_HEIGHT(f);
Dest.Y = vpos;
}
else
{
Scroll.Top = vpos;
Scroll.Bottom = FRAME_HEIGHT(f) - n;
Dest.Y = vpos + n;
}
Scroll.Left = 0;
Scroll.Right = FRAME_WIDTH(f);
Dest.X = 0;
save_highlight = HLmode(0);
Fill.Char.AsciiChar = 0x20;
Fill.Attributes = CAttr;
ScrollConsoleScreenBuffer(CurScreen, &Scroll, NULL, Dest, &Fill);
/*
* here we have to deal with a win32 console flake: If the scroll
* region looks like abc and we scroll c to a and fill with d we get
* cbd... if we scroll block c one line at a time to a, we get cdd...
* Jove expects cdd consistently... So we have to deal with that
* here... (this also occurs scrolling the same way in the other
* direction.
*/
if (n > 0)
{
if (Scroll.Bottom < Dest.Y)
{
for (i = Scroll.Bottom; i < Dest.Y; i++)
{
MoveCursor(i, 0);
ClearEndOfLine(FRAME_WIDTH(f));
}
}
}
else
{
nb = Dest.Y + (Scroll.Bottom - Scroll.Top) + 1;
if (nb < Scroll.Top)
{
for (i = nb; i < Scroll.Top; i++)
{
MoveCursor(i, 0);
ClearEndOfLine(FRAME_WIDTH(f));
}
}
}
Cursor.X = 0;
Cursor.Y = vpos;
HLmode(save_highlight);
}
/*
* HLmode -- Changes attribute to use when drawing characters to control
* highlighting
*/
static int
HLmode(int new_highlight)
{
static int Highlight = 0;
int old_highlight;
old_highlight = Highlight;
Highlight = (new_highlight != 0); /* map to boolean */
if (Highlight)
{
CAttr = CAttrReverse;
}
else
{
CAttr = CAttrNormal;
}
return old_highlight;
}
/*
* Call this when about to modify line at position VPOS and change whether it
* is highlighted.
*/
void
ChangeLineHighlight(int new_highlight, int vpos, int first_unused_hpos)
{
HLmode(new_highlight);
MoveCursor(vpos, 0);
ClearEndOfLine(first_unused_hpos);
}
/*
* External interface to control of standout mode. Call this when about to
* modify line at position VPOS and not change whether it is highlighted.
*/
void
ReassertLineHighlight(int highlight, int vpos)
{
HLmode(highlight);
vpos; /* pedantic compiler silencer */
}
#undef LEFT
#undef RIGHT
#define LEFT 1
#define RIGHT 0
void
ScrollLine(int dist, int direction)
{
/*
* The idea here is to implement a horizontal scroll in one line to
* implement delete and half of insert.
*/
SMALL_RECT Scroll;
COORD Dest;
CHAR_INFO Fill;
FRAME_PTR f = PICK_FRAME();
Scroll.Top = Cursor.Y;
Scroll.Bottom = Cursor.Y;
if (direction == LEFT)
{
Scroll.Left = Cursor.X+dist;
Scroll.Right = FRAME_WIDTH(f)-1;
}
else
{
Scroll.Left = Cursor.X;
Scroll.Right = FRAME_WIDTH(f)-dist-1;
}
Dest.X = Cursor.X;
Dest.Y = Cursor.Y;
Fill.Char.AsciiChar = 0x20;
Fill.Attributes = CAttr;
ScrollConsoleScreenBuffer(CurScreen, &Scroll, NULL, Dest, &Fill);
}
/*
* if start is zero insert blanks instead of a string at start ?
*/
void
InsertGlyphs(register GLYPH *start, register int len)
{
ScrollLine(len, RIGHT);
/*
* move len chars to the right starting at Cursor, fill with blanks
*/
if (start)
{
/*
* print the first len characters of start, Cursor.X adjusted
* by WriteGlyphs.
*/
WriteGlyphs(start, len);
}
else
{
ClearEndOfLine(Cursor.X + len);
}
}
void
WriteGlyphs(register GLYPH *string, register int len)
{
register char *ptr;
register unsigned int glyphLength = GLYPH_TABLE_LENGTH;
Lisp_Object *glyphBase = GLYPH_TABLE_BASE;
int i;
GLYPH glyph;
FRAME_PTR f = PICK_FRAME();
WORD *attrs;
char *chars;
attrs = alloca(len*sizeof(*attrs));
chars = alloca(len*sizeof(*chars));
if (attrs == NULL || chars == NULL)
{
printf("alloca failed in WriteGlyphs\n");
return;
}
/*
* We have to deal with the glyph indirection...go over the glyph
* buffer and extract the characters.
*/
ptr = chars;
while (--len >= 0)
{
glyph = *string++;
if (glyph > glyphLength)
{
*ptr++ = glyph & 0xFF;
continue;
}
GLYPH_FOLLOW_ALIASES(glyphBase, glyphLength, glyph);
if (GLYPH_FACE(glyph) != 0)
printf("Glyph face is %d\n", GLYPH_FACE(glyph));
if (GLYPH_SIMPLE_P(glyphBase, glyphLength, glyph))
{
*ptr++ = glyph & 0xFF;
continue;
}
for (i = 0; i < GLYPH_LENGTH(glyphBase, glyph); i++)
{
*ptr++ = (GLYPH_STRING(glyphBase, glyph))[i];
}
}
/* Number of characters we have in the buffer */
len = ptr-chars;
/*
* Fill in the attributes for these characters.
*/
memset(attrs, CAttr, len*sizeof(*attrs));
/*
* Write the attributes.
*/
if (!WriteConsoleOutputAttribute(CurScreen, attrs, len, Cursor, &i))
{
printf("Failed writing console attributes.\n");
fflush(stdout);
}
/*
* Write the characters.
*/
if (!WriteConsoleOutputCharacter(CurScreen, chars, len, Cursor, &i))
{
printf("Failed writing console characters.\n");
fflush(stdout);
}
Cursor.X += len;
MoveCursor(Cursor.Y, Cursor.X);
}
void
DeleteGlyphs(int n)
{
/*
* delete chars means scroll chars from Cursor.X + n to Cursor.X,
* anything beyond the edge of the screen should come out empty...
*/
ScrollLine(n, LEFT);
}
void
RingBell(void)
{
Beep(666, 100); /* wha'da-ya-want-fer-nothin'? */
}
/* Reset to the original console mode but don't get rid of our console
For suspending emacs */
void
RestoreConsole(void)
{
UnsetKbd();
SetConsoleActiveScreenBuffer(PrevScreen);
}
/* Put our console back up, for ending a suspended session */
void
TakeConsole(void)
{
ResetKbd();
SetConsoleActiveScreenBuffer(CurScreen);
}
void
ResetTerminalModes(void)
{
UnsetKbd();
SetConsoleActiveScreenBuffer(PrevScreen);
CloseHandle(CurScreen);
CurScreen = NULL;
}
void
SetTerminalModes(void)
{
CONSOLE_CURSOR_INFO cci;
if (CurScreen == NULL)
{
ResetKbd();
CurScreen = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
0, NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL);
if (CurScreen == INVALID_HANDLE_VALUE)
{
printf("CreateConsoleScreenBuffer failed in ResetTerm\n");
printf("LastError = 0x%lx\n", GetLastError());
printf("CreateConsoleScreenBuffer failed in ResetTerm\n");
printf("LastError = 0x%lx\n", GetLastError());
fflush(stdout);
exit(0);
}
SetConsoleActiveScreenBuffer(CurScreen);
/* make cursor big and visible */
cci.dwSize = 100;
cci.bVisible = TRUE;
(void) SetConsoleCursorInfo(CurScreen, &cci);
}
}
/*
* hmmm... perhaps these let us bracket screen changes so that we can flush
* clumps rather than one-character-at-a-time...
*
* we'll start with not moving the cursor while an update is in progress
*/
void
UpdateBegin(FRAME_PTR f)
{
}
void
UpdateEnd(FRAME_PTR f)
{
SetConsoleCursorPosition(CurScreen, Cursor);
}
void
SetTerminalWindow(int size)
{
}
void
UnsetKbd(void)
{
SetConsoleMode(Keyboard, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT);
}
void
ResetKbd(void)
{
Keyboard = GetStdHandle(STD_INPUT_HANDLE);
SetConsoleMode(Keyboard, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
}
void
initialize_win_nt_display(void)
{
CONSOLE_SCREEN_BUFFER_INFO Info;
cursor_to_hook = MoveCursor;
raw_cursor_to_hook = MoveCursor;
clear_to_end_hook = ClearToEnd;
clear_frame_hook = ClearFrame;
clear_end_of_line_hook = ClearEndOfLine;
ins_del_lines_hook = InsDelLines;
change_line_highlight_hook = ChangeLineHighlight;
reassert_line_highlight_hook= ReassertLineHighlight;
insert_glyphs_hook = InsertGlyphs;
write_glyphs_hook = WriteGlyphs;
delete_glyphs_hook = DeleteGlyphs;
ring_bell_hook = RingBell;
reset_terminal_modes_hook = ResetTerminalModes;
set_terminal_modes_hook = SetTerminalModes;
set_terminal_window_hook = SetTerminalWindow;
update_begin_hook = UpdateBegin;
update_end_hook = UpdateEnd;
read_socket_hook = Win32ReadSocket;
mouse_position_hook = Win32MousePosition;
PrevScreen = GetStdHandle(STD_OUTPUT_HANDLE);
SetTerminalModes();
GetConsoleScreenBufferInfo(CurScreen, &Info);
meta_key = 1;
CAttr = Info.wAttributes & 0xFF;
CAttrNormal = CAttr;
CAttrReverse = ((CAttr & 0xf) << 4) + ((CAttr & 0xf0) >> 4);
FRAME_HEIGHT(selected_frame) = Info.dwSize.Y; /* lines per page */
FRAME_WIDTH(selected_frame) = Info.dwSize.X; /* characters per line */
MoveCursor(0, 0);
ClearFrame();
}
DEFUN_P(Fset_screen_color, (Lisp_Object foreground, Lisp_Object background));
DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
"Set screen colors.")
(foreground, background)
Lisp_Object foreground;
Lisp_Object background;
{
CAttrNormal = XFASTINT(foreground) + (XFASTINT(background) << 4);
CAttrReverse = XFASTINT(background) + (XFASTINT(foreground) << 4);
Frecenter (Qnil);
return Qt;
}
DEFUN_P(Fset_cursor_size, (Lisp_Object size));
DEFUN ("set-cursor-size", Fset_cursor_size, Sset_cursor_size, 1, 1, 0,
"Set cursor size.")
(size)
Lisp_Object size;
{
CONSOLE_CURSOR_INFO cci;
cci.dwSize = XFASTINT(size);
cci.bVisible = TRUE;
(void) SetConsoleCursorInfo(CurScreen, &cci);
return Qt;
}
_VOID_
syms_of_ntterm ()
{
defsubr(&Sset_screen_color);
defsubr(&Sset_cursor_size);
}